function results = ensemble_train(settings)
% -------------------------------------------------------------------------
% Ensemble Classification | June 2011 | public version 1.0
% -------------------------------------------------------------------------
% Contact: jan@kodovsky.com
% -------------------------------------------------------------------------
% References:
% [1] - J. Kodovsky, J. Fridrich, and V. Holub. Ensemble classifiers for
% steganalysis of digital media. IEEE Transactions on Information Forensics
% and Security. Currently under review.
% -------------------------------------------------------------------------
% settings
%   .cover - cover feature file(s); a string or a cell array (example_4.m)
%   .stego - stego feature file(s); a string or a cell array (example_4.m)
%   .seed_trntst - PRNG seed for training/testing set division
%   .seed_subspaces (default = random) - PRNG seed for random subspace
%         generation
%   .d_sub - random subspace dimensionality; an integer (e.g. 200)
%   .L - number of random subspaces / base learners; an integer (e.g. 50)
%   .output (default = './output/date_x.log') - log file where both the
%         progress and the results of the classification are stored
%   .verbose (default = 1) - turn on/off screen output
%   .keep_cov (default = 0) - a memory demanding speed-up of the search
%         for d_sub; by default turned off; turn on only when the search
%         for d_sub is to be performed, and only if your system has enough
%         memory; otherwise turn this option off
%   .ignore_warnings (default = 1) - ignore 'MATLAB:nearlySingularMatrix'
%         warning during the FLD training => speed-up; ignoring these
%         warnings had no effect on performance in our experiments; if the
%         value is set to 0, warnings will not be ignored; in that case,
%         the diagonal of the ill-conditioned covariance matrix will be
%         iteratively weighted with increasing weights until the matrix is
%         well conditioned (see the code for details)
%
% According to our experiments, these values are sufficient for most of the
% steganalysis tasks (different algorithms and features). Nevertheless, any
% of these parameters can be modified before calling the ensemble if
% desired.
% -------------------------------------------------------------------------

% check settings, set default values, initial screen print
settings = check_initial_setup(settings);
% pre-generate seeds for random subspaces and bootstrap samples
PRNG = generate_seeds(settings);
% create training set
[Xc,Xs,settings] = create_training2(settings);
% initialization of the search for k (if requested)
results = [];
OOB.error = 1;

% create structures for caching covariance matrices
sigCstored.k = zeros(settings.max_number_base_learners,1,'uint16');
sigCstored.sig = cell(settings.max_number_base_learners,1);
sigSstored.k = zeros(settings.max_number_base_learners,1,'uint16');
sigSstored.sig = cell(settings.max_number_base_learners,1);

if settings.verbose
    fprintf('Full dimensionality = %i\n',settings.max_dim);
end

% initialization
base_learner = cell(settings.max_number_base_learners,1);

% loop over individual base learners
for i=1:settings.L
    %%% RANDOM SUBSPACE GENERATION
    rand('state',double(PRNG.subspaces(i)));
    base_learner{i}.subspace = randperm(settings.max_dim);
    subspace = base_learner{i}.subspace(1:settings.k);
    
    %%% BOOTSTRAP INITIALIZATION
    OOB = bootstrap_initialization(PRNG,Xc,Xs,OOB,i,settings);
    
    %%% TRAINING PHASE
    base_learner{i} = FLD_training(Xc,Xs,i,base_learner{i}, OOB, subspace,settings,sigCstored,sigSstored);
end % while next_random_subspace

% found the best value of k so far
OPTIMAL_L = settings.L;
OPTIMAL_K = settings.k;
MIN_OOB = OOB.error;
clear OOB Xc Xs;

% final output and logging
results = collect_final_results(settings,OPTIMAL_K,OPTIMAL_L,MIN_OOB,base_learner,results);

end